#! /bin/sh 
# name		$TOOLS/backup/dbbackup_begin 
# 
# purpose	Performs a hot or cold backup of the database. 
#		This script is called by dbbackup. 
# 
# usage		$TOOLS/backup/dbbackup_begin <dbname> <backup>  
#			<special task> 
# 
# parameters	$1=dbname 
#		$2=backup type 
#		$3=special task 
# 
# 
# .............................................................. 
# set local variables 
# .............................................................. 
ERRMSG=" 
`basename $0`: syntax error:  
    dbbackup_begin <dbname> <hot|cold|nobackup> <special task>. 
" 
# 
# parameters 
# 
if [ "$1" ] 
then DBNAME=$1 
else echo $ERRMSG  >&2 
     exit 1  
fi 
if [ "$2" ] 
then BACKUP=$2 
else echo $ERRMSG  >&2 
     exit 1 
fi 
if [ "$3" ] 
then SPECIAL_TASK=$3 
else SPECIAL_TASK=" " 
fi 
 
# 
# booleans 
#  
TRUE=0 
FALSE=1 
SHUTDOWN_FAILED_B=1 
RESTART_FAILED_B=1 
 
# 
# local variables 
# 
JOBNAME="$TOOLS/backup/dbbackup_begin" 
JOBNAME_SHORT="dbbackup_begin" 
LOGDIR="$TOOLS/db_admin/db_$DBNAME/log/" 
DBBACKUP="$LOGDIR/datafile_`date '+%y%m%d'.log" 
CTLFILES="$LOGDIR/control_`date '+%y%m%d'.log" 
ARCHLOGS="$LOGDIR/archlog_`date '+%y%m%d'.log" 
ALERTLOG="$LOGDIR/alertlog_`date '+%y%m%d'.log" 
SPECIALOG="$LOGDIR/special_`date '+%y%m%d'.log" 
 
# Location of these commands is system dependent  
WALL="/usr/sbin/wall" 
CKSUM="/bin/cksum" 
CMP="/bin/cmp" 
 
BANNER="$TOOLS/db_admin/db_${DBNAME}/banner/status" 
CKSUM_SIZE_ERR="${JOBNAME_SHORT}: fatal error in cksum size comparison." 
CKSUM_VALUE_ERR="${JOBNAME_SHORT}: fatal error in cksum value comparison." 
CKSUM_VALUE_WAR="${JOBNAME_SHORT}: warning in cksum value comparison." 
CMP_ERR="${JOBNAME_SHORT}: fatal error in cmp." 
ARCERR="${JOBNAME_SHORT}: fatal error in archive log copy." 
THISNODE=`uname -n` 
 
# .............................................................. 
# begin 
# .............................................................. 
 
# 
# check for database online 
# 
STATUS=`ps -fu oracle | grep "ora_[a-z]*_${DBNAME}" ` 
if [ $? != 0 ]; then 
  # There are no background processes running, or database is down  
  if [ "$BACKUP" = "hot" ]; then 
    # hot backup does not make sense. 
    echo "${JOBNAME_SHORT}: Database is not online. Switching to cold backup"   
    echo "${JOBNAME_SHORT}: Database is not online. Switching to cold 
backup">&2 
    BACKUP="cold" 
  else 
    # for cold backup this is fine 
    echo "${JOBNAME_SHORT}: Database is already down.  Continuing." 
  fi 
else  
  # since database is already up 
  if [ "$BACKUP" = "cold" ]; then 
 
    #  
    # broadcast shutdowns, write your own banners 
    # 
     $WALL $TOOLS/db_admin/db_${DBNAME}/banner/shutdown_15min.banner 
     sleep 300 
     $WALL $TOOLS/db_admin/db_${DBNAME}/banner/shutdown_5min.banner 
     sleep 240 
     $WALL $TOOLS/db_admin/db_${DBNAME}/banner/shutdown_1min.banner 
     sleep 60 
    #  
    # shutdown using appropriate shutdown scripts 
    # Before the shutdown ensure that the logfile being used is archived 
    # 
    echo "${JOBNAME_SHORT}: Shutting down immediate." 
 
     svrmgrl >/dev/null <<EOF 
     connect internal 
     alter system switch logfile; 
     shutdown immediate; 
     exit 
EOF 
    STATUS=`ps -fu oracle | grep "ora_[a-z]*_${DBNAME}" ` 
    if [ $? = 0 ]; then 
    echo "${JOBNAME_SHORT}: Error in database shutdown. Exiting." 
    exit 
    fi 
    # 
    # kill sqlnet processes 
    # 
    echo "${JOBNAME_SHORT}: killing sqlnet v2 processes." 
    PROCS=`ps -ef |grep oracle${DBNAME} |grep -v grep |awk '{print $2}'` 
    if [ x$PROCS = x ]; then 
    echo "${JOBNAME_SHORT}: no processes to kill" 
    else 
    echo "${JOBNAME_SHORT}: killing processes $PROCS" 
    kill $PROCS 
    fi 
    echo " " 
  fi 
fi 
 
if [ "$BACKUP" = "cold" ]; then 
   echo "${JOBNAME_SHORT}: Starting up restrict." 
   svrmgrl >/dev/null <<EOF 
   connect internal 
   startup mount restrict 
   exit 
EOF 
    STATUS=`ps -fu oracle | grep "ora_[a-z]*_${DBNAME}" ` 
    if [ $? != 0 ]; then 
    echo "${JOBNAME_SHORT}: Error in database startup. Exiting." 
    exit 
    fi 
 
fi 
 
# ...................................................................... 
# begin backup 
# ...................................................................... 
# 
# build database file list 
# 
 
echo "${JOBNAME_SHORT}: building dynamic parameter file." 
 
if [ $BACKUP = "hot" ]; then 
  svrmgrl >/dev/null <<EOF 
  connect internal 
  set termout off 
  spool $DBBACKUP; 
  select file_name,tablespace_name from sys.dba_data_files 
  order by tablespace_name,file_name; 
  spool off; 
  exit; 
EOF 
 
else  
  svrmgrl >/dev/null <<EOF 
  connect internal 
  set termout off 
  spool $DBBACKUP; 
  select name from v\$datafile; 
  spool off; 
  exit; 
EOF 
 
fi 
 
svrmgrl >/dev/null <<EOF 
connect internal 
set termout off 
spool $CTLFILES; 
select name from v\$controlfile; 
spool off; 
spool $ARCHLOGS; 
select value from v\$parameter where name='log_archive_dest'; 
spool off; 
spool $ALERTLOG; 
select value from v\$parameter where name='background_dump_dest'; 
spool off; 
exit 
EOF 
 
# Check the dynamic parameter file size 
if [ -z $DBBACKUP ]; then  
   echo "${JOBNAME_SHORT}: fatal error during backup file creation.  Backup 
aborting." 
   return 
fi 
 
# 
# shutdown 
# 
if [ $BACKUP = "cold" ]; then 
  echo "${JOBNAME_SHORT}: Shutting down immediate."   
svrmgrl >/dev/null <<EOF 
connect internal 
shutdown immediate 
exit 
EOF 
 
  STATUS=`ps -fu oracle | grep "ora_[a-z]*_${DBNAME}" ` 
  if [ $? = 0 ]; then 
    echo "${JOBNAME_SHORT}: error in shutdown. Cold backup aborting." 
    SHUTDOWN_FAILED_B="$TRUE" 
  else 
    echo "${JOBNAME_SHORT}: Database is shutdown." 
    echo "${JOBNAME_SHORT}: move alert log." 
    ALERT=`sed -e 's/[    ]*$//' -e '/selected\.$/d' \ 
     -e '/^---.*--$/d'  -e '/^VALUE/d' $ALERTLOG` 
    mv ${ALERT}/alert_${DBNAME}.log \ 
    ${ALERT}/alert_${DBNAME}.log_`date '+%y%m%d'` 
  fi 
 
fi 
 
# 
# Begin backup 
# 
if [ $SHUTDOWN_FAILED_B = $FALSE ]; then 
  echo " " 
  echo "${JOBNAME_SHORT}:  Starting $BACKUP backup using $DBBACKUP..." 
  # 
  # Move BACKUPDIR to BACKUPDIROLD 
    # Files from the old backup are moved to a different location 
    # before starting another backup job.  
    # If you have backed up these files to tape (recommended), you  
    # might want to remove these files instead of moving.  
  # 
  if [ `ls ${BACKUPDIR} | wc -l` != 0 ]; then 
    for FILE in ${BACKUPDIR}/* 
    do 
    mv $FILE $BACKUPDIROLD 
    done 
  fi  
  # 
  # Make a backup copy of alert log  
  # 
  if [ $BACKUP = "cold" ]; then 
   cp ${ALERT}/alert_${DBNAME}.log_`date '+%y%m%d'` \ 
   ${BACKUPDIR} 
  fi 
  # 
  # check hot backup status 
  # 
  if  [ $BACKUP = "hot" ]; then 
    svrmgrl <<EOF 
    connect internal 
    select * from v\$backup; 
    exit 
EOF 
  fi 
  # 
  # begin reading dynamic parameter file 
  # 
  if [ $BACKUP = "hot" ]; then 
    SED="sed -e '/selected\.$/d' -e '/^---.*--$/d'  -e '/^FILE_NAME/d' \ 
	$DBBACKUP" 
  else 
    SED="sed -e '/selected\.$/d' -e '/^---.*--$/d'  -e '/^NAME/d' $DBBACKUP" 
  fi 
 
  eval $SED | while read FILE TABLESPACE 
  do 
    if [ $BACKUP = "hot" ]; then 
      svrmgrl <<EOF 
      connect internal 
      alter tablespace $TABLESPACE begin backup; 
      exit 
EOF 
    fi 
    # 
    # copy a database file 
    # 
 
    echo "${JOBNAME_SHORT}: cp $FILE $BACKUPDIR" 
    DATAFILE=`basename $FILE` 
 
    # It is possible that database files under different directories have the 
    # same name. We have to take care that we don't accidentally overwrite 
    # a file because of this. One possible way to do this is: 
    #   if [ -f ${BACKUPDIR}/${DATAFILE} ]; then 
    #      NEWNAME=`dirname $FILE | tr / _` 
    #      cp $FILE ${BACKUPDIR}/${DATAFILE}${NEWNAME} 
    #   fi 
 
    cp $FILE $BACKUPDIR 
    STATUS=$? 
    if [ "$STATUS" != 0 ]; then 
      echo  "${JOBNAME_SHORT}: error during file copy $FILE." 
    fi 
    if [ $BACKUP = "hot" ]; then 
      echo "${JOBNAME_SHORT}: $CKSUM $FILE $BACKUPDIR/$DATAFILE" 
      $CKSUM $FILE $BACKUPDIR/$DATAFILE 
      CKSUM_OUT=`$CKSUM $FILE $BACKUPDIR/$DATAFILE` 
      echo $CKSUM_OUT | read VALUE1 SIZE1 NAME1 VALUE2 SIZE2 NAME2 
      if [ "$VALUE1" != "$VALUE2" ]; then 
        echo "$CKSUM_VALUE_WAR" 
      fi 
      if [ "$SIZE1" != "$SIZE2" ]; then 
        echo "$CKSUM_SIZE_ERR" 
      fi 
    else 
      echo "${JOBNAME_SHORT}: $CMP $FILE $BACKUPDIR/$DATAFILE" 
      $CMP $FILE $BACKUPDIR/$DATAFILE 
      STATUS="$?" 
      if [ "$STATUS" != 0 ]; then 
         echo "$CMP_ERR" 
      fi  
    fi 
    if [ $BACKUP = "hot" ]; then 
      svrmgrl <<EOF 
      connect internal 
      alter tablespace $TABLESPACE end backup; 
      exit 
EOF 
    fi 
  done 
  # 
  # check hot backup status 
  # 
  if  [ $BACKUP = "hot" ]; then 
    svrmgrl <<EOF 
    connect internal 
    select * from v\$backup; 
    exit 
EOF 
  fi 
  # 
  # Backup control files 
  # 
    # 
    # control files 
    # 
 if [ $BACKUP = "hot" ]; then 
    echo "${JOBNAME_SHORT}: backing up controlfile to \ 
		${BACKUPDIR}/${DBNAME}_control01.ctl" 
    svrmgrl <<EOF 
    connect internal 
    alter database backup controlfile to '${BACKUPDIR}/control01.ctl'; 
    exit 
EOF 
    # 
  else 
   sed -e '/rows selected\.$/d' -e '/^---.*--$/d'  -e '/^NAME/d' $CTLFILES \ 
	| while read FILE 
   do 
    # 
    # copy a control file 
    # 
    echo "${JOBNAME_SHORT}: cp $FILE $BACKUPDIR" 
    DATAFILE=`basename $FILE` 
 
    # It is possible that control files under different directories have the 
    # same name. We have to take care that we don't accidentally overwrite 
    # a file because of this. One possible way to do this is: 
    #   if [ -f ${BACKUPDIR}/${DATAFILE} ]; then 
    #      NEWNAME=`dirname $FILE | tr / _` 
    #      cp $FILE ${BACKUPDIR}/${DATAFILE}${NEWNAME} 
    #   fi 
 
    cp $FILE $BACKUPDIR 
    STATUS=$? 
    if [ "$STATUS" != 0 ]; then 
      echo  "${JOBNAME_SHORT}: error during file copy $FILE." 
    fi 
    echo "${JOBNAME_SHORT}: $CMP $FILE $BACKUPDIR/$DATAFILE" 
    $CMP $FILE $BACKUPDIR/$DATAFILE 
    STATUS="$?" 
    if [ "$STATUS" != 0 ]; then 
       echo "$CMP_ERR" 
    fi  
   done 
 fi 
 
  # 
  # archive logs 
  # 
  # Make sure that you backup archive logs only and not the online 
  # redo logs. 
  # 
  # force a log switch  
  # 
  if [ $BACKUP = "hot" ]; then 
    svrmgrl <<EOF 
    connect internal 
    alter system switch logfile; 
    exit 
EOF 
  # Sleep for sometime, till the log file is copied. 
   sleep 120 
  fi 
  # copy archive logs  
  # 
   ARC=`sed -e 's/[    ]*$//' -e '/selected\.$/d' \ 
    -e '/^---.*--$/d'  -e '/^VALUE/d' $ARCHLOGS` 
  if [ -f $ARCOLD/* ]; then 
   echo " " 
   echo "${JOBNAME_SHORT}: Delete previous backup archive logs..." 
   for I in $ARCOLD/* 
     do 
      ls -l $I 
       ARCNAME=`basename $I` 
       rm $ARCOLD/$ARCNAME 
       STATUS="$?" 
       if [ "$STATUS" != 0 ]; then 
        echo "${JOBNAME_SHORT}: error deleting old archive log: 
$ARCOLD/$ARCNAME" 
       fi 
    done 
  else    echo " " 
          echo "${JOBNAME_SHORT}: No old archive logs to delete." 
  fi 
 
  if [ -f $ARC/* ]; then 
    echo " " 
    echo "${JOBNAME_SHORT}: Copying archive logs..." 
    for I in $ARC/* 
      do 
     	ls -l $I 
       	ARCNAME=`basename $I` 
	echo "${JOBNAME_SHORT}: cp $ARC/$ARCNAME $ARCOLD" 
     	cp $ARC/$ARCNAME $ARCOLD 
	STATUS="$?" 
      	if [ "$STATUS" != 0 ]; then 
            echo "$ARCERR" 
	fi 
	echo "${JOBNAME_SHORT}: $CMP $ARC/$ARCNAME $ARCOLD/$ARCNAME" 
	$CMP $ARC/$ARCNAME $ARCOLD/$ARCNAME 
        STATUS="$?" 
        if [ "$STATUS" != 0 ]; then 
            echo "$CMP_ERR" 
            echo "${JOBNAME_SHORT}: Archive log deletion skipped." 
       	else echo "${JOBNAME_SHORT}: $CKSUM $ARC/$ARCNAME 
$ARCOLD/$ARCNAME"  
  	  $CKSUM $ARC/$ARCNAME $ARCOLD/$ARCNAME	 
          CKSUM_OUT=`$CKSUM $ARC/$ARCNAME $ARCOLD/$ARCNAME` 
          echo $CKSUM_OUT | read VALUE1 SIZE1 NAME1 VALUE2 SIZE2 NAME2 
          if [ "$VALUE1" != "$VALUE2" -o "$SIZE1" != "$SIZE2" ]; then 
            echo "$DIFFERR" 
            echo "${JOBNAME_SHORT}: Archive log deletion skipped." 
          else rm $ARC/$ARCNAME 
            if [ $? != 0 ]; then 
              echo "${JOBNAME_SHORT}: Archive deletion failed." 
            fi 
          fi 
        fi 
      done 
  else echo "${JOBNAME_SHORT}: Found no archives to copy." 
  fi 
 
 
 if [ $BACKUP = "cold" ]; then 
  # startup 
  # 
    #  
    # dba mode tasks 
    # 
    if [ "$SPECIAL_TASK" != " " ]; then 
        echo "${JOBNAME_SHORT}: Running DBA mode task..." 
 
      svrmgrl >/dev/null <<EOF 
      connect intrenal 
      startup restrict 
      exit 
EOF 
      STATUS=`ps -fu oracle | grep "ora_[a-z]*_${DBNAME}" ` 
      if [ $? != 0 ]; then 
        echo "${JOBNAME_SHORT}: error in database startup."  >&2 
        echo "	Skipping ${SPECIAL_TASK}."  >&2 
      else 
          . ${SPECIAL_TASK} > $SPECIALOG 2>&1 
 
      svrmgrl >/dev/null <<EOF 
      connect internal 
      shutdown 
      exit 
EOF 
     fi 
   fi 
    # 
    # startup 
    # 
   svrmgrl >/dev/null <<EOF 
   connect internal 
   startup mount; 
   alter database archivelog; 
   alter database open; 
   exit 
EOF 
    STATUS=`ps -fu oracle | grep "ora_[a-z]*_${DBNAME}" ` 
    if [ $? != 0 ]; then 
      echo "${JOBNAME_SHORT}: error in database startup."  
      echo "${JOBNAME_SHORT}: error in database startup."  >&2 
      RESTART_FAILED_B=0 
    else 
      echo "${JOBNAME_SHORT}: Database restarted." 
       $WALL $TOOLS/db_admin/db_${DBNAME}/banner/db_online.banner       
    fi 
 fi 
 
fi 


